/****************************************************************************
 SPI极性（CPOL）和相位（CPHA）的说明：
 CPOL： 0表示SCLK空闲时为低电平；1表示SCLK空闲时为高电平
 CPHA： 0表示采样从片选信号拉低后SCLK的第一个时钟沿开始；1表示采样从片选信号拉低后SCLK的第二个时钟沿开始
	在16通道读出版本中，采用芯片TMUX1208控制各个芯片的SPI片选信号，需要三个输入信号A0,A1,A2：
	A2		|	A1		|	A0		|	chip_name	|	CPOL	|	CPHA
	CS_en3	|	CS_en2	|	CS_en1	|				|			|
	--------|-----------|-----------|---------------|-----------|-----------
	0		|	0		|	1		|	ADS5294		|	1		|	1
	--------|-----------|-----------|---------------|-----------|-----------
	0		|	1		|	0		|	DACX0508-1	|	1		|	0
	--------|-----------|-----------|---------------|-----------|-----------
	0		|	1		|	1		|ADG714+DACX0508|	1		|	0
	--------|-----------|-----------|---------------|-----------|-----------
	1		|	0		|	0		|	AD9508		|	1		|	1
	--------|-----------|-----------|---------------|-----------|-----------
	--------|-----------|-----------|---------------|-----------|-----------
	0		|	0		|	0		|	all CS are pulled high (default)

	-- CPOL -- 0表示空闲时SCLK为低电位；1表示空闲时SCLK为高电位
	-- CPHA -- 0表示从SCLK的第一个跳变沿开始采样；1表示从SCLK的第二个跳变沿开始采样

	在空闲状态下(A0,A1,A2)=(0,0,0)；当需要对某个芯片进行配置时，只需将(A0,A1,A2)设置
	成对应该芯片的一组值，在配置完成之后再恢复至(0,0,0)即可。
****************************************************************************/

#include "COMMON.h"

#ifndef _SPI_H_
#define _SPI_H_

#define _SPI_SUCCESS_	0
#define _SPI_FAILURE_ 	1

//	===========================================================================
//	SPI configuration
//	Note that CS is now determined via (A0,A1,A2), with an extra signal A2
typedef struct{
/*    uint32_t bit_num;  // can be only one of 8bits, 24bits, 32bits*/
    uint32_t S1;
    uint32_t S0;
	uint32_t cpol;
	uint32_t cpha;
	uint32_t A2;
	uint32_t A1;
	uint32_t A0;

	int status_bit_pos;	// 为了抓取不同的SPI模块的status,分别设置一个bit_pos
	char devname[64];	// 63 bits should be enough to store device name(s)
} SPI_CONFIG;

uint32_t setup_SPI( SPI_CONFIG * spi_cfg, 
                    uint32_t S1,
                    uint32_t S0,
				    uint32_t cpol, 
				    uint32_t cpha, 
				    uint32_t A2,
				    uint32_t A1,
				    uint32_t A0,
				    int status_bit_pos,
				    char *devname );

uint32_t setup_SPI_by_device_name( SPI_CONFIG * spi_cfg, char *devname );

//	===========================================================================
//	SPI data container
typedef struct{
	uint32_t size;				//	不同芯片通过SPI进行配置时需要发送的数据可能存在差异
	uint32_t *reg_addr;
	uint32_t *reg_val;
	uint32_t *reg_addr_val; 	// 不同芯片要求的SPI数据bits数不一定相同,因此需要分别实现相应的初始化函数
} SPI_DATA;

uint32_t spi_data_alloc( SPI_DATA *spi_data, uint32_t data_size );
uint32_t spi_data_free( SPI_DATA *spi_data );

void print_spi_config( SPI_CONFIG *cfg );

//  旧版本,在拼接reg_addr_val时,地址向左移动固定的16位
uint32_t spi_data_set( SPI_DATA *spi_data, uint32_t idx, uint32_t addr, uint32_t val );

//  不同芯片要求的SPI数据bits数不一定相同,因此需要分别实现相应的初始化函数,
//  这里增加一个可以根据需求指定左移位数的函数
uint32_t spi_data_set_LS(   SPI_DATA *spi_data, 
                            uint32_t idx, 
                            uint32_t addr, 
                            uint32_t val, 
                            uint32_t LS_bit_num );

//	===========================================================================
//	SPI片选信号配置函数（旧版本）
void set_SPI_A2( uint32_t* gpio_reg, uint32_t A2 );
void set_SPI_A1( uint32_t* gpio_reg, uint32_t A1 );
void set_SPI_A0( uint32_t* gpio_reg, uint32_t A0 );

//  配置SPI传输数据位数
void set_SPI_S1( uint32_t* gpio_reg, uint32_t S1 );
void set_SPI_S0( uint32_t* gpio_reg, uint32_t S0 );

void pull_down_SPI_CS( uint32_t* gpio_reg, SPI_CONFIG * spi_cfg );
void pull_up_SPI_CS( uint32_t* gpio_reg, SPI_CONFIG * spi_cfg );

void set_SPI_CPOL( uint32_t* gpio_reg, uint32_t CPOL );
void set_SPI_CPHA( uint32_t* gpio_reg, uint32_t CPHA );

// set_SPI_DAISY不再使用
void set_SPI_DAISY( uint32_t* gpio_reg, uint32_t DAISY );

//	===========================================================================
//	SPI reset (trigger) signal
void pulse_SPI_RST(uint32_t* gpio_reg);

//	===========================================================================
//	wrappered functions to perform SPI communications

//  1) ADS5294：
//  2) DACx0508：
//  3) Daisy： 
//  4) AD9508： 24bits
//  因此决定实现以下三个版本的SPI数据发送函数，这三个函数分别对应FPGA端的三个SPI模块实例化。
//  
//  SPI模块实例化的选择由*gpio_reg中的SPI_S1,SPI_S0两个信号控制
//  --------|-----------|-----------
//  SPI_S1  |   SPI_S0  |   BITS
//  --------|-----------|-----------
//  0       |   0       |   X   
//  --------|-----------|-----------
//  0       |   1       |   8 bits
//  --------|-----------|-----------
//  1       |   0       |   24 bits
//  --------|-----------|-----------
//  1       |   1       |   32 bits
//  
//  在PL端, 用一个多路选择器根据SPI_S1,SPI_S0信号选择具体由哪个SPI模块实例来完成SPI通信(数据发送)
//  TODO:后期可以进一步优化,将SPI_S1,SPI_S0转变成A2,A1,A0的组合!!!

uint32_t send_spi_data_bits( uint32_t* gpio_reg, 
						     uint32_t* gpio2_reg, 
						     uint32_t* gpio_in_reg, 
						     SPI_CONFIG *spi_config,
						     uint32_t data );

uint32_t send_spi_data_bits_daisy_chain_mode(uint32_t* gpio_reg, 
					                         uint32_t* gpio2_reg, 
					                         uint32_t* gpio_in_reg, 
					                         SPI_CONFIG *spi_config );

uint32_t send_spi_data( uint32_t* gpio_reg, 
					    uint32_t* gpio2_reg, 
					    uint32_t* gpio_in_reg, 
					    SPI_CONFIG *spi_config,
					    SPI_DATA *spi_data );
					    
uint32_t send_spi_data_daisy_chain_mode( uint32_t* gpio_reg, 
					                     uint32_t* gpio2_reg, 
					                     uint32_t* gpio_in_reg, 
					                     SPI_CONFIG *spi_config,
					                     SPI_DATA *spi_data );
#endif
